package com.ehotting.edsta.circuitDesign.gen.element.helper;


import com.ehotting.edsta.circuitDesign.SpringContextHelper;
import com.ehotting.edsta.circuitDesign.domain.EsElement;
import com.ehotting.edsta.circuitDesign.enums.ChannelTypeOutEnum;
import com.ehotting.edsta.circuitDesign.exception.LoggerTar;
import com.ehotting.edsta.circuitDesign.gen.ScriptConstants;
import com.ehotting.edsta.circuitDesign.service.impl.EsElementServiceImpl;

import com.ehotting.eaf.core.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.stream.Collectors;

public class ElementDataHelper {



    public static double DIFF_VALUE = 0.1;

    public static List<EsElement> findByCode(String code){
        EsElementServiceImpl esElementService= SpringContextHelper.getBean(EsElementServiceImpl.class);
        EsElement esElement = esElementService.findOneByCode(code);
        if (esElement == null){
            return new ArrayList<>();
        }
        return esElementService.findByType(esElement.getType());
    }

    public static List<EsElement> findByType(Integer type){
        EsElementServiceImpl esComponentService= SpringContextHelper.getBean(EsElementServiceImpl.class);
        return esComponentService.findByType(type);
    }



    public static List<EsElement> findAll(){
        EsElementServiceImpl esElementService= SpringContextHelper.getBean(EsElementServiceImpl.class);
        return esElementService.selectEsElementList(null);
    }

    public static EsElement findByValue(List<EsElement> componentAllList, String code, Double value){
        List<Map<String,Object>> resultList = new ArrayList<>();
        for(EsElement component : componentAllList){
            double diff = Math.abs(NumberHelper.parseDouble(component.getValue()) - value);
            if(diff < ElementDataHelper.DIFF_VALUE){
                Map<String,Object> map = new HashMap<>();
                map.put(ScriptConstants.DIFF,diff);
                map.put(code,component);
                resultList.add(map);
            }
        }
        if(resultList.size()==0){
            return null;
        }
        Map<String,Object> map = first(resultList);
        return (EsElement)map.get(code);
    };


    public static EsElement findByProp(List<EsElement> componentAllList, String code, String prop, Double value){
        List<Map<String,Object>> resultList = new ArrayList<>();
        for(EsElement component : componentAllList){
            if(component.getProps()==null){
                continue;
            }
            if(!component.getProps().containsKey(prop)){
                continue;
            }
            double diff = Math.abs((Double)component.getProps().get(prop) - value);
            if(diff < ElementDataHelper.DIFF_VALUE){
                Map<String,Object> map = new HashMap<>();
                map.put(ScriptConstants.DIFF,diff);
                map.put(code,component);
                resultList.add(map);
            }
        }
        if(resultList.size()==0){
            return null;
        }
        Map<String,Object> map = first(resultList);
        if(map!=null){
            return (EsElement)map.get(code);
        }
        return null;

    };


    public static void replace(List<Map<String,Object>> outMapList, EsElement oldComponent, EsElement newComponent, String code){

        for(Map<String,Object> m : outMapList){
            if(m.containsKey(code)){
                Object o = m.get(code);
                if(o instanceof EsElement){
                    EsElement c = (EsElement) o;
                    if(c.getId().equals(oldComponent.getId())){
                        m.put(code,newComponent);
                    }
                }
            }
        }

        List<Map<String,Object>> newList = outMapList.stream().distinct().collect(Collectors.toList());
        outMapList.clear();
        outMapList.addAll(newList);

    }

    /**
     * 重置全局变量，比如:r1List,r2List,r3List;
     * @param outMapList
     * @param rxList
     * @param code
     */
    public static void resetList(List<Map<String,Object>> outMapList, List<EsElement> rxList, String code){
        List<EsElement> list = new ArrayList<>();
        for(Map<String,Object> m : outMapList){
            if(m.containsKey(code)){
                Object o = m.get(code);
                if(o instanceof EsElement){
                    list.add((EsElement)o);
                }
            }
        }
        rxList.clear();
        rxList.addAll(list);
    }


    /**
     * 从list中找出最优化对象
     * @param list
     * @return
     */
    public static Map<String,Object> first(List<Map<String,Object>> list){
        return first( list,null);
    }

    /**
     * 针对code,从list中找出最优化对象
     * @param list
     * @param code
     * @return
     */
    public static Map<String,Object> first(List<Map<String,Object>> list, String code){
        Map<String,Object> map = null;
        if(list.size()==0){
            return null;
        }
        for(Map<String,Object> temp: list){
            if(code != null ){
                if(!temp.containsKey(code)){
                    continue;
                }
            }
            if(map==null){
                map = temp;
                continue;
            }
            if((double)map.get(ScriptConstants.DIFF) > (double)temp.get(ScriptConstants.DIFF)){
                map = temp;
            }
        }
        return map;
    }


    public static void addIfNotExist(List<EsElement> esElementList, EsElement esElement ){
        if(!esElementList.contains(esElement)){
            esElementList.add(esElement);
        }
    }

    public static List<Map<String, EsElement>> convertElement(List<Map<String, Object>> outMapList){
        List<Map<String, EsElement>> list = outMapList.stream().map(map->{
            Set<String> set = map.keySet();
            Map<String, EsElement> newMap = new HashMap<>();
            for(String key: set){
                Object o = map.get(key);
                if(o instanceof EsElement){
                    newMap.put(key,(EsElement)o);
                }
            }
            return newMap;
        }).collect(Collectors.toList());
        return list;
    }


    public static List<Map<String, Object>> convertObject(List<Map<String, EsElement>> outMapList){
        List<Map<String, Object>> list = outMapList.stream().map(map->{
            Set<String> set = map.keySet();
            Map<String, Object> newMap = new HashMap<>();
            for(String key: set){
                newMap.put(key,map.get(key));
            }
            return newMap;
        }).collect(Collectors.toList());
        return list;
    }




    public static  double prop(EsElement element, String propKey){
        double rx_prop = 0.00;
        if(element.getProps()!=null  && element.getProps().containsKey(propKey)){
            String o = String.valueOf(element.getProps().get(propKey));
            rx_prop = NumberHelper.parseDouble(o);
        }
        return rx_prop;
    }

    /**
     * 电源输出电压匹配规则
     * @param powerVoltage  电源供电电压属性
     * @param sensor  传感模块模块电压属性
     * @param controller  处理器电压属性
     * @return 电源电路输出电压包含其它模块电路输入电压
     */
    public static boolean voltageJudgment(Object powerVoltage, Object sensor,Object controller,Object cirName){

        if (powerVoltage == null || sensor == null || controller == null){
            return false;
        }
        String[] senArr = sensor.toString().replace("[","").replace("]","")
                .replace(" ","").split(",");
        double[] senDouble = Arrays.stream(senArr).mapToDouble(Double::parseDouble).toArray();
        String[] conArr = controller.toString().replace("[","").replace("]","")
                .replace(" ","").split(",");
        double[] conDouble = Arrays.stream(conArr).mapToDouble(Double::parseDouble).toArray();
        if (senArr.length == 0 || conArr.length == 0){
            return false;
        }

        String[] powerArr = powerVoltage.toString().replace("[","").replace("]","")
                .replace(" ","").split(",");
        double[] powerDouble = Arrays.stream(powerArr).mapToDouble(Double::parseDouble).toArray();
        String powStr = Arrays.toString(powerDouble);
        for (Double s : senDouble){
            if (!powStr.contains(s.toString())){
                return false;
            }
        }
        // 电源的输出电压 包涵 控制器输入电压之一即可
        boolean conB = true;
        for (Double c : conDouble){
            if( powStr.contains(c.toString()) ){
                conB = false;
            }
        }
        if (conB){
            return false;
        }

        return true;
    }

    /**
     * 来源匹配 0:国产 1:非国产
     * @param sensor 传感电路来源
     * @param other  其他电路来源
     * @return  传感电路全为国产时，电源电路和处理电路也必须为国产。
     *          传感电路存在非国产时，电源电路和处理电路不做要求。
     */
    public static boolean sourceJudgment(Object sensor,Object other,Object cirName){

        if(sensor == null || other == null
                || StringUtils.isEmpty(sensor.toString())
                || StringUtils.isEmpty(other.toString())){
            return false;
        }

        String senStr = sensor.toString();
        String otStr = other.toString();

        if(senStr.contains("1") || !otStr.contains("1")){
            return true;
        }
        return false;
    }

    /**
     * 控制/读取方式匹配
     * @param outputType  传感电路的输出类型（模拟:0  数字：1）
     * @param sensor  传感电路的控制/读取方式
     * @param controller  处理电路的内部接口类型
     * @return 输出类型存在数字时，处理电路的控制/读取方式必须包含传感电路的控制/读取方式
     */
    //todo 控制/读取方式 ok
    public static boolean controlReadJudgment(Object outputType,Object sensor,Object controller,Object cirName){

        if(argNull(outputType, sensor, controller)){
            return false;
        }

        String[] outputSplit = outputTypeToStrings(outputType);
        for(String ou : outputSplit){
            if(Double.valueOf(ou)==1){
                String conStr = controller.toString();
                String[] senArr = sensor.toString().replace("[", "").replace("]", "")
                        .replace(" ", "").split(",");
                for (String s : senArr) {
                    if (!s.equals("GPIO") && !conStr.contains(s)) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    /**
     * 模拟通道数匹配
     * @param outputType   传感电路的输出类型（模拟:0  数字：1）
     * @param sensor 模拟输出通道数
     * @param controller   处理电路的通道数
     * @return 输出类型存在模拟时,处理电路的通道数必须包含大于传感电路的通道数
     */
    public static boolean analogChannelNumJudgment(Object outputType,Object sensor,Object controller,Object cirName){
        boolean aNull = argNull(outputType, sensor, controller);
        if(aNull){
            return false;
        }

        String[] outputSplit = outputTypeToStrings(outputType);
        for(String ou : outputSplit){
            if(Double.valueOf(ou)==0){
                double sensorNum = Double.valueOf(sensor.toString());
                double controllerNum = Double.valueOf(controller.toString());
                return controllerNum >= sensorNum;
            }
        }
        return true;
    }

    private static boolean argNull(Object...args){
        for (Object a : args){
            if(a == null || StringUtils.isEmpty(a.toString())){
                return true;
            }
        }
        return false;
    }

    /**
     * 采样率匹配
     * @param outputType  传感电路的输出类型（模拟:0  数字：1）
     * @param sensor  传感电路选择完毕后的采样率
     * @param controller   处理电路的采样率
     * @return 输出类型存在模拟时，处理电路的采样率必须包含大于传感电路的采样率
     */
    //todo 采样率 ok
    public static boolean sampleJudgment(Object outputType,Object sensor,Object controller,Object cirName){

        if(argNull(outputType, sensor, controller)){
            return false;
        }

        String[] outputTypeSplit = outputTypeToStrings(outputType);
        for (String out : outputTypeSplit){
            if(Double.valueOf(out)==0){
                double sensorDouble = Double.valueOf(sensor.toString());
                double controllerDouble = Double.valueOf(controller.toString());
               return controllerDouble >= sensorDouble;
            }
        }
        return true;
    }

    /**
     * ADC分辨率（ADC位数）:模拟
     * @param outputType 传感电路的输出类型（模拟:0  数字：1）
     * @param sensor 传感电路选择完毕后的ADC分辨率（传感电路方案ADC分辨率）
     * @param controller 处理电路的ADC分辨率
     * @return 输出类型存在模拟时，处理电路的ADC分辨率必须包含大于传感电路的ADC分辨率
     */
    //todo ADC分辨率（ADC位数） ok
    public static boolean ADCSamplingBitJudgment(Object outputType,Object sensor,Object controller,Object cirName){


        if(argNull(outputType, sensor, controller)){
            return false;
        }

        String[] outputTypeSplit = outputTypeToStrings(outputType);
        for (String out : outputTypeSplit){
            if(Double.valueOf(out)==0){
                double sensorDouble = Double.valueOf(sensor.toString());
                double controllerDouble = Double.valueOf(controller.toString());
                return controllerDouble >= sensorDouble;
            }
        }
        return true;
    }


    /**
     * 数字通道数匹配
     * @param digitalChanNum  传感电路选择完毕后的数字通道数
     * @param controller  处理器的数字通道数
     * @return 数字通道不为零时，处理电路的数字通道数必须包含大于传感电路的数字通道数
     */
    //todo 数字通道数 ok
    public static boolean digitalChannalNumJudgment(Object digitalChanNum,Object controller,Object cirName){
        if(argNull(digitalChanNum, controller)){
            return false;
        }

        double digChNum = Double.valueOf(digitalChanNum.toString());
        if(digChNum>0) {
            double conNum = Double.valueOf(controller.toString());
            return conNum >= digChNum;
        }
        return true;
    }

    /**
     * 存储容量匹配
     * @param analogueChanNum  传感电路选择完毕后的模拟通道数
     * @param adcSamplingBit  传感电路选择完毕后的精度
     * @param samplingLength  方案最大存储长度
     * @param controller  处理电路的存储容量
     * @return 处理电路的存储容量大于模拟通道数n*(最大ADC精度k/8)*最大存储长度t
     */
    //todo 存储容量 ok
    public static boolean storageCapacityJudgment(Object analogueChanNum, Object adcSamplingBit,
                                                    Object samplingLength, Object controller,Object cirName){

        if(argNull(analogueChanNum, adcSamplingBit, samplingLength, controller)){
            return false;
        }

        if(Double.valueOf(adcSamplingBit.toString()) > 0) {
            double maxADCSamBit = Double.valueOf(adcSamplingBit.toString());
            double ceil = Math.ceil(maxADCSamBit / 8);
            double maxLen = Double.valueOf(samplingLength.toString());
            double chanNum = Double.valueOf(analogueChanNum.toString());

            double con = Double.valueOf(controller.toString());
            return con >= chanNum * ceil * maxLen;

        }
        return true;
    }

    /**
     * 存储速率匹配
     * @param analogueChanNum 传感电路选择完毕后的模拟通道数
     * @param adcSamplingBit 传感电路选择完毕后的精度
     * @param sampleMax 方案最大采样率
     * @param controller 处理电路的存储速率
     * @return 处理电路的存储速率大于模拟通道数n*(最大ADC精度k/8)*最大采样率s
     */
    public static boolean storageRateJudgment(Object analogueChanNum, Object adcSamplingBit,
                                                  Object sampleMax, Object controller,Object cirName){


        if(argNull(analogueChanNum, adcSamplingBit, sampleMax, controller)){
            return false;
        }

        if(Double.valueOf(adcSamplingBit.toString()) > 0) {
            double maxADC = Double.valueOf(adcSamplingBit.toString());
            double ceil = Math.ceil(maxADC / 8);
            double chanNum = Double.valueOf(analogueChanNum.toString());
            double samLen = Double.valueOf(sampleMax.toString());

            double con = Double.valueOf(controller.toString());
            return con >= chanNum * ceil * samLen;
        }
        return true;
    }

    private static String[] outputTypeToStrings(Object outputType){
        return outputType.toString().replace("[", "")
                .replace("]", "")
                .replace(" ","")
                .split(",");
    }
}